﻿using LightCAD.Core.Elements;
using LightCAD.Three;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.Json;
using System.Text.Json.Serialization;
using System.Threading.Tasks;

namespace LightCAD.Core
{
    public enum Curve2dType
    {
        None = 0,
        Point2d = 1,
        Line2d = 2,
        Rect2d = 3,
        Arc2d = 4,
        Circle2d = 5,
        Spline2d = 6,
        Polyline2d = 7,
        Polygon2d = 8,
        Path2d = 9,
    }

    public interface ICurve2d : ICloneable
    {
        string Name { get; set; }
        Curve2dType Type { get; }
        bool IsClosed { get; }
        object Source { get; set; }
        void Copy(ICurve2d src);
        ICurve2d Clone();
    }

    public static class Curve2dUtils
    {
        public static ICurve2d Create(Curve2dType type)
        {
            switch (type)
            {
                case Curve2dType.Point2d:
                    return new Point2d();
                case Curve2dType.Line2d:
                    return new Line2d();
                case Curve2dType.Rect2d:
                    return new Rect2d();
                case Curve2dType.Arc2d:
                    return new Arc2d();
                case Curve2dType.Circle2d:
                    return new Circle2d();
                case Curve2dType.Spline2d:
                    return new Spline2d();
                case Curve2dType.Polygon2d:
                    return new Polygon2d();
                case Curve2dType.Polyline2d:
                    return new Polyline2d();
                case Curve2dType.Path2d:
                    return new Path2d();
            }
            return null;
        }

        internal static void ReadProperties(ref JsonElement jele, ICurve2d curve)
        {
            if (jele.TryGetProperty(nameof(curve.Name), out JsonElement nameProp))
                curve.Name = nameProp.GetString();

            switch (curve.Type)
            {
                case Curve2dType.Point2d:
                    {
                        var point = curve as Point2d;
                        point.XY = jele.ReadVector2dProperty(nameof(point.XY));
                        break;
                    }
                case Curve2dType.Line2d:
                    {
                        var line = curve as Line2d;
                        line.Start = jele.ReadVector2dProperty(nameof(line.Start));
                        line.End = jele.ReadVector2dProperty(nameof(line.End));
                        break;
                    }
                case Curve2dType.Rect2d:
                    {
                        var rect = curve as Rect2d;
                        rect.Min = jele.ReadVector2dProperty(nameof(rect.Min));
                        rect.Max = jele.ReadVector2dProperty(nameof(rect.Max));
                        break;
                    }
                case Curve2dType.Arc2d:
                    {
                        var arc = curve as Arc2d;
                        arc.Center = jele.ReadVector2dProperty(nameof(arc.Center));
                        arc.Radius = jele.ReadDoubleProperty(nameof(arc.Radius));
                        arc.StartAngle = jele.ReadDoubleProperty(nameof(arc.StartAngle));
                        arc.EndAngle = jele.ReadDoubleProperty(nameof(arc.EndAngle));
                        break;
                    }
                case Curve2dType.Circle2d:
                    {
                        var cir = curve as Circle2d;
                        cir.Center = jele.ReadVector2dProperty(nameof(cir.Center));
                        cir.Radius = jele.ReadDoubleProperty(nameof(cir.Radius));
                        break;
                    }
                case Curve2dType.Spline2d:
                    {
                        break;
                    }
                case Curve2dType.Polygon2d:
                    {
                        var polygon = curve as Polygon2d;
                        polygon.Points = jele.ReadListProperty<Vector2d>(nameof(polygon.Points)).ToArray();
                        break;
                    }
                case Curve2dType.Polyline2d:
                    {
                        var polyline = curve as Polyline2d;
                        polyline.Points = jele.ReadListProperty<Vector2d>(nameof(polyline.Points)).ToArray();
                        break;
                    }
                case Curve2dType.Path2d:
                    {
                        var path = curve as Path2d;
                        path.Curves = jele.ReadListProperty<ICurve2d>(nameof(path.Curves)).ToArray();
                        break;
                    }
            }
        }

        internal static void WriteProperties(Utf8JsonWriter writer, ICurve2d curve,JsonSerializerOptions soptions)
        {
            if (!string.IsNullOrEmpty(curve.Name))
                writer.WriteStringProperty(nameof(curve.Name), curve.Name);

            switch (curve.Type)
            {
                case Curve2dType.Point2d:
                    {
                        var point = curve as Point2d;
                        writer.WriteVector2dProperty(nameof(point.XY), point.XY);
                        break;
                    }
                case Curve2dType.Line2d:
                    {
                        var line = curve as Line2d;
                        writer.WriteVector2dProperty(nameof(line.Start), line.Start);
                        writer.WriteVector2dProperty(nameof(line.End), line.End);
                        break;
                    }
                case Curve2dType.Rect2d:
                    {
                        var rect = curve as Rect2d;
                        writer.WriteVector2dProperty(nameof(rect.Min), rect.Min);
                        writer.WriteVector2dProperty(nameof(rect.Max), rect.Max);
                        break;
                    }
                case Curve2dType.Arc2d:
                    {
                        var arc = curve as Arc2d;
                        writer.WriteVector2dProperty(nameof(arc.Center), arc.Center);
                        writer.WriteNumberProperty(nameof(arc.Radius), arc.Radius);
                        writer.WriteNumberProperty(nameof(arc.StartAngle), arc.StartAngle);
                        writer.WriteNumberProperty(nameof(arc.EndAngle), arc.EndAngle);
                        break;
                    }
                case Curve2dType.Circle2d:
                    {
                        var cir = curve as Circle2d;
                        writer.WriteVector2dProperty(nameof(cir.Center), cir.Center);
                        writer.WriteNumberProperty(nameof(cir.Radius), cir.Radius);
                        break;
                    }
                case Curve2dType.Spline2d:
                    {
                        break;
                    }
                case Curve2dType.Polygon2d:
                    {
                        var polygon = curve as Polygon2d;
                       writer.WriteCollectionProperty<Vector2d>(nameof(polygon.Points), polygon.Points, soptions);
                        break;
                    }
                case Curve2dType.Polyline2d:
                    {
                        var polyline = curve as Polyline2d;
                        writer.WriteCollectionProperty<Vector2d>(nameof(polyline.Points), polyline.Points, soptions);
                        break;
                    }
                case Curve2dType.Path2d:
                    {
                        var path = curve as Path2d;
                        writer.WriteCollectionProperty<ICurve2d>(nameof(path.Curves), path.Curves, soptions, (w, c) => w.WriteCurve2dObject(c,soptions));
                        break;
                    }
            }
        }
    }
}
